package com.iisigroup.log.analysis;

import com.iisigroup.log.analysis.model.InfoUnit;
import com.iisigroup.log.analysis.model.StuckThreadRecord;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * sample log url 
 * 140.92.86.160
 * /MHNFS/SDATA/WLSLOG/192.1.0.83/
 */
public class AnalysisForStuck {
    private final static Logger LOGGER = LoggerFactory.getLogger(AnalysisForStuck.class);
    private final static String preFixpatternStr = "####<\\d{4}\\/\\d{1,}\\/\\d{1,}.*CST>.*";
    private final static String suffFixpatternStr = ">.*";
    private final static String condition = "[STUCK]";
    private final static String packageName ="tw.gov.moi.";
    public  static  final  int  BUFFER =  1024 ;  
    public  static  final  String EXT =  ".gz" ;  
    public static void main(String[] args) {
       
        if(args ==null || args.length== 0){
            System.out.println("Please specific the folder.." );
        }else{
            final  Properties properties = System.getProperties();
            final String pathName = args[0];
            final File srcFile =  new File(pathName);
            final String path = (String)properties.get("user.dir");
            final File srcFile01 =  new File(path + File.separator +pathName);
            
            if(!srcFile.exists() && !srcFile01.exists()){
                System.out.println("Your specfic file path is not exist .." );
            } else if (srcFile.exists() ){
                final String result =   getSummaryStuckLog(srcFile);
                System.out.println(result);
            }else if (srcFile01.exists()){
                final  String result =   getSummaryStuckLog(srcFile01);
                System.out.println(result);
            }
           
        }
    }
    private static  boolean qualified(String line){
        final String regExpr =".*tw.gov.moi.*.service.*";        
        return line.contains(packageName)  && line.matches(regExpr) ;
    } 
    public static String getSummaryStuckLog(final File... srcFile){
        String result =null;
        final StringBuilder sb = new StringBuilder();
        if (ArrayUtils.isNotEmpty(srcFile)) {

            final AnalysisForStuck instance = new AnalysisForStuck();
            final List<InfoUnit> data = instance.getInfoSrc(srcFile);
            final Map<String, Integer> satatics = new HashMap<String, Integer>();
            final Iterator<InfoUnit> iterator = data.iterator();
            while (iterator.hasNext()) {
                final InfoUnit unit = iterator.next();
                final List<String> list = unit.getOriginalData();
                for (String line : list) {
                    if (qualified(line)) {
                        Integer value = satatics.get(line);
                        if (value == null) {
                            value = Integer.valueOf(0);
                        }
                        satatics.put(line, Integer.valueOf(value.intValue() + 1));
                        break;
                    }
                }
                iterator.remove();
            }
            data.clear();
            //節省記憶體
            final Set<Entry<String, Integer>> entrySet = satatics.entrySet();

            for (final Entry<String, Integer> entryUnit : entrySet) {
                final String key = entryUnit.getKey();
                final Integer value = entryUnit.getValue();
                sb.append(String.format("%s , %s \n", key, value.toString()));
            }

        }
        result =sb.toString();
        return result;
    }
   public List<StuckThreadRecord> extractStuckLogs(final File... srcFile)  {
	   final List<StuckThreadRecord> result = new ArrayList<StuckThreadRecord>();
	   for (File unitFile : srcFile) {
           if(unitFile.isDirectory()){
        	   final List<StuckThreadRecord> unitList =  extractStuckLogs ( unitFile.listFiles());
        	   result.addAll(unitList);
               continue;
           }
           List<InfoUnit>   intData = getInfoSrc(unitFile);            
           
           final Iterator<InfoUnit> iterator = intData.iterator();
           while (iterator.hasNext()) {
               final InfoUnit unit = iterator.next();
               StuckThreadRecord unitData=   Converter.convert(unit);
               result.add(unitData);
               iterator.remove();              
           }
       }
	   return result;
   }
    public List<String> extractStuckLog(final File... srcFile)  {
        List<String> result = new ArrayList<String>();
        for (File unitFile : srcFile) {
            if(unitFile.isDirectory()){
                continue;
            }
            List<InfoUnit>   intData = getInfoSrc(unitFile);;
             
            
            final Iterator<InfoUnit> iterator = intData.iterator();
            while (iterator.hasNext()) {
                final InfoUnit unit = iterator.next();
                final StringBuilder sb = new StringBuilder();
                for (String line : unit.getOriginalData()) {
                    sb.append(line).append("\n");
                }
                result.add(sb.toString());
                iterator.remove();
            }
        }
        return result;
    }

    public List<InfoUnit> getInfoSrc(final File... srcFile) {
        final List<InfoUnit> result = new ArrayList<InfoUnit>();
        BufferedReader br = null;
        try {
            for (File unitFile : srcFile) {
                if(unitFile.isDirectory()){
                    getInfoSrc(unitFile.listFiles());
                    continue;
                }
                if (unitFile.getName().contains(EXT)) {
                    final GzipAbstractProcess aGzipAbstractProcess = new GzipAbstractProcess() {
                        @Override
                        List<InfoUnit> proceesDecompress(File tmpFile) {
                            return getInfoSrc(tmpFile);
                        }
                    };
                    final List<InfoUnit> intData = aGzipAbstractProcess.decompress(unitFile);
                    result.addAll(intData);
                }else{
                    br = new BufferedReader(new FileReader(unitFile));
                    InfoUnit unit = null;
                    List<String> tmp = null;
                    while (br.ready()) {
                        final String unitLine = br.readLine();
                        final Matcher matcher = Pattern.compile(preFixpatternStr).matcher(unitLine);
                        String prefixData = null;
                        if (matcher.matches()) {
                            final int groupCount = matcher.groupCount();
                            prefixData = matcher.group(groupCount);
                            tmp = new ArrayList<String>();
                            tmp.add(unitLine);
                        }
                        if (tmp != null && (prefixData == null || prefixData.trim().length() == 0)) {
                            tmp.add(unitLine);
                            if (unitLine.matches(suffFixpatternStr)) {
                                //表示是結尾
                                unit = new InfoUnit();
                                unit.setOriginalFilePath(unitFile.getCanonicalPath());
                                unit.getOriginalData().addAll(tmp);
                                if (unit.getOriginalData().size() > 0 && unit.getOriginalData().get(0).contains(condition)) {
                                    result.add(unit);
                                }
                                tmp = null;
                            }
                        }
                    }  
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            LOGGER.error(e.getMessage(), e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
        return result;
    }
    public abstract class GzipAbstractProcess {
        public List<InfoUnit>  decompress(final File unitFile){
        	String filePath = null;
            List<InfoUnit> intData =null;
            File tmpFile = null;
            OutputStream os = null;
            GZIPInputStream gis = null;
            try {
            	filePath = unitFile.getCanonicalPath();
                gis = new GZIPInputStream(new FileInputStream(unitFile));
                tmpFile = File.createTempFile("logstatic", ".log");
                os = new FileOutputStream(tmpFile);
                int count;
                byte data[] = new byte[BUFFER];
                while ((count = gis.read(data, 0, BUFFER)) != -1) {
                    os.write(data, 0, count);
                }
                intData = proceesDecompress(tmpFile);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                LOGGER.error(e.getMessage(), e);
            } finally {
                if (tmpFile != null && tmpFile.exists()) {
                    tmpFile.delete();
                }
                try {
                    if (gis != null)
                        gis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    LOGGER.error(e.getMessage(), e);
                }
                try {
                    if (os != null)
                        os.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    LOGGER.error(e.getMessage(), e);
                }
            }
                if(intData!= null)
			for (final InfoUnit unit : intData) {
				unit.setOriginalFilePath(filePath);
			}
            return intData;
        }
        abstract List<InfoUnit> proceesDecompress(File tmpFile) ;
    }
}
